/*
 * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package com.sun.imageio.plugins.jpeg;

import javax.imageio.metadata.IIOMetadataFormat;
import javax.imageio.metadata.IIOMetadataFormatImpl;
import javax.imageio.ImageTypeSpecifier;

import java.awt.color.ICC_Profile;
import java.awt.color.ColorSpace;
import java.awt.image.ColorModel;

import java.util.List;
import java.util.ArrayList;

public class JPEGImageMetadataFormat extends JPEGMetadataFormat {

    private static JPEGImageMetadataFormat theInstance = null;

    private JPEGImageMetadataFormat() {
        super(JPEG.nativeImageMetadataFormatName, CHILD_POLICY_ALL);

        addElement("JPEGvariety", JPEG.nativeImageMetadataFormatName, CHILD_POLICY_CHOICE);

        addElement("markerSequence", JPEG.nativeImageMetadataFormatName, CHILD_POLICY_SEQUENCE);

        addElement("app0JFIF", "JPEGvariety", CHILD_POLICY_SOME);

        addStreamElements("markerSequence");

        addElement("app14Adobe", "markerSequence", CHILD_POLICY_EMPTY);

        addElement("sof", "markerSequence", 1, 4);

        addElement("sos", "markerSequence", 1, 4);

        addElement("JFXX", "app0JFIF", 1, Integer.MAX_VALUE);

        addElement("app0JFXX", "JFXX", CHILD_POLICY_CHOICE);

        addElement("app2ICC", "app0JFIF", CHILD_POLICY_EMPTY);

        addAttribute("app0JFIF", "majorVersion", DATATYPE_INTEGER, false, "1", "0", "255", true, true);
        addAttribute("app0JFIF", "minorVersion", DATATYPE_INTEGER, false, "2", "0", "255", true, true);
        List resUnits = new ArrayList();
        resUnits.add("0");
        resUnits.add("1");
        resUnits.add("2");
        addAttribute("app0JFIF", "resUnits", DATATYPE_INTEGER, false, "0", resUnits);
        addAttribute("app0JFIF", "Xdensity", DATATYPE_INTEGER, false, "1", "1", "65535", true, true);
        addAttribute("app0JFIF", "Ydensity", DATATYPE_INTEGER, false, "1", "1", "65535", true, true);
        addAttribute("app0JFIF", "thumbWidth", DATATYPE_INTEGER, false, "0", "0", "255", true, true);
        addAttribute("app0JFIF", "thumbHeight", DATATYPE_INTEGER, false, "0", "0", "255", true, true);

        addElement("JFIFthumbJPEG", "app0JFXX", CHILD_POLICY_SOME);
        addElement("JFIFthumbPalette", "app0JFXX", CHILD_POLICY_EMPTY);
        addElement("JFIFthumbRGB", "app0JFXX", CHILD_POLICY_EMPTY);

        List codes = new ArrayList();
        codes.add("16"); // Hex 10
        codes.add("17"); // Hex 11
        codes.add("19"); // Hex 13
        addAttribute("app0JFXX", "extensionCode", DATATYPE_INTEGER, false, null, codes);

        addChildElement("markerSequence", "JFIFthumbJPEG");

        addAttribute("JFIFthumbPalette", "thumbWidth", DATATYPE_INTEGER, false, null, "0", "255", true, true);
        addAttribute("JFIFthumbPalette", "thumbHeight", DATATYPE_INTEGER, false, null, "0", "255", true, true);

        addAttribute("JFIFthumbRGB", "thumbWidth", DATATYPE_INTEGER, false, null, "0", "255", true, true);
        addAttribute("JFIFthumbRGB", "thumbHeight", DATATYPE_INTEGER, false, null, "0", "255", true, true);

        addObjectValue("app2ICC", ICC_Profile.class, false, null);

        addAttribute("app14Adobe", "version", DATATYPE_INTEGER, false, "100", "100", "255", true, true);
        addAttribute("app14Adobe", "flags0", DATATYPE_INTEGER, false, "0", "0", "65535", true, true);
        addAttribute("app14Adobe", "flags1", DATATYPE_INTEGER, false, "0", "0", "65535", true, true);

        List transforms = new ArrayList();
        transforms.add("0");
        transforms.add("1");
        transforms.add("2");
        addAttribute("app14Adobe", "transform", DATATYPE_INTEGER, true, null, transforms);

        addElement("componentSpec", "sof", CHILD_POLICY_EMPTY);

        List procs = new ArrayList();
        procs.add("0");
        procs.add("1");
        procs.add("2");
        addAttribute("sof", "process", DATATYPE_INTEGER, false, null, procs);
        addAttribute("sof", "samplePrecision", DATATYPE_INTEGER, false, "8");
        addAttribute("sof", "numLines", DATATYPE_INTEGER, false, null, "0", "65535", true, true);
        addAttribute("sof", "samplesPerLine", DATATYPE_INTEGER, false, null, "0", "65535", true, true);
        List comps = new ArrayList();
        comps.add("1");
        comps.add("2");
        comps.add("3");
        comps.add("4");
        addAttribute("sof", "numFrameComponents", DATATYPE_INTEGER, false, null, comps);

        addAttribute("componentSpec", "componentId", DATATYPE_INTEGER, true, null, "0", "255", true, true);
        addAttribute("componentSpec", "HsamplingFactor", DATATYPE_INTEGER, true, null, "1", "255", true, true);
        addAttribute("componentSpec", "VsamplingFactor", DATATYPE_INTEGER, true, null, "1", "255", true, true);
        List tabids = new ArrayList();
        tabids.add("0");
        tabids.add("1");
        tabids.add("2");
        tabids.add("3");
        addAttribute("componentSpec", "QtableSelector", DATATYPE_INTEGER, true, null, tabids);

        addElement("scanComponentSpec", "sos", CHILD_POLICY_EMPTY);

        addAttribute("sos", "numScanComponents", DATATYPE_INTEGER, true, null, comps);
        addAttribute("sos", "startSpectralSelection", DATATYPE_INTEGER, false, "0", "0", "63", true, true);
        addAttribute("sos", "endSpectralSelection", DATATYPE_INTEGER, false, "63", "0", "63", true, true);
        addAttribute("sos", "approxHigh", DATATYPE_INTEGER, false, "0", "0", "15", true, true);
        addAttribute("sos", "approxLow", DATATYPE_INTEGER, false, "0", "0", "15", true, true);

        addAttribute("scanComponentSpec", "componentSelector", DATATYPE_INTEGER, true, null, "0", "255", true, true);
        addAttribute("scanComponentSpec", "dcHuffTable", DATATYPE_INTEGER, true, null, tabids);
        addAttribute("scanComponentSpec", "acHuffTable", DATATYPE_INTEGER, true, null, tabids);
    }

    public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) {
        // All images can have these
        if (elementName.equals(getRootName()) || elementName.equals("JPEGvariety") || isInSubtree(elementName, "markerSequence")) {
            return true;
        }

        // If it is an element in the app0jfif subtree, just check
        // that the image type is JFIF compliant.
        if ((isInSubtree(elementName, "app0JFIF")) && JPEG.isJFIFcompliant(imageType, true)) {
            return true;
        }

        return false;
    }

    public static synchronized IIOMetadataFormat getInstance() {
        if (theInstance == null) {
            theInstance = new JPEGImageMetadataFormat();
        }
        return theInstance;
    }
}
